//地上有一个m行n列的方格，从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动，它每次可以向左、右、上、下移动一
//格（不能移动到方格外），也不能进入行坐标和列坐标的数位之和大于k的格子。例如，当k为18时，机器人能够进入方格 [35, 37] ，因为3+5+3+7=18。但
//它不能进入方格 [35, 38]，因为3+5+3+8=19。请问该机器人能够到达多少个格子？ 
//
// 
//
// 示例 1： 
//
// 输入：m = 2, n = 3, k = 1
//输出：3
// 
//
// 示例 2： 
//
// 输入：m = 3, n = 1, k = 0
//输出：1
// 
//
// 提示： 
//
// 
// 1 <= n,m <= 100 
// 0 <= k <= 20 
// 
// Related Topics 深度优先搜索 广度优先搜索 动态规划 👍 504 👎 0

package leetcode.editor.offer;

// 13. 机器人的运动范围
// https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/

class JiQiRenDeYunDongFanWeiLcof {
    public static void main(String[] args) {
        Solution solution = new JiQiRenDeYunDongFanWeiLcof().new Solution();
        System.out.println(solution.movingCount(3, 1, 0));
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        /*int m, n, k;
        boolean[][] visited;

        public int movingCount(int m, int n, int k) {
            this.m = m;
            this.n = n;
            this.k = k;
            visited = new boolean[m][n];
            // 从 (0,0) 开始
            return dfs(0, 0, 0, 0);
        }

        */

        /**
         * dfs深搜
         * 时间复杂度 O(MN)O(MN) ： 最差情况下，机器人遍历矩阵所有单元格，此时时间复杂度为 O(MN)O(MN) 。
         * 空间复杂度 O(MN)O(MN) ： 最差情况下，Set visited 内存储矩阵所有单元格的索引，使用 O(MN)O(MN) 的额外空间。
         *
         * @param i  代表此时的x
         * @param j  代表此时的y
         * @param si 此时x的位和
         * @param sj 此时y的位和
         * @return
         *//*
        public int dfs(int i, int j, int si, int sj) {
            // 越界或者已经访问过
            if (i >= m || j >= n || k < si + sj || visited[i][j]) return 0;
            visited[i][j] = true;   // 访问过
            return 1 + dfs(i + 1, j, (i + 1) % 10 == 0 ? si - 8 : si + 1, sj) + dfs(i, j + 1, si, (j + 1) % 10 == 0 ? sj - 8 : sj + 1);
        }*/

        /**
         * bfs搜索
         *
         * @param m
         * @param n
         * @param k
         * @return
         */
        /*public int movingCount(int m, int n, int k) {
            int res = 0;    // 表示机器人可以走动结果
            Queue<int[]> queue = new LinkedList<>();    // 队列，记录遍历过的数组
            queue.offer(new int[]{0, 0, 0, 0});
            boolean[][] visited = new boolean[m][n]; // 表示是否走过
            while (!queue.isEmpty()) {
                int[] poll = queue.poll();
                int i = poll[0], j = poll[1], si = poll[2], sj = poll[3];
                if (i >= m || j >= n || k < si + sj || visited[i][j]) continue;  // 越界或者相加大于k，或者访问过的，直接跳过
                visited[i][j] = true;
                res++;
                queue.offer(new int[]{i + 1, j, (i + 1) % 10 == 0 ? si - 8 : si + 1, sj}); // 下边元素入栈
                queue.offer(new int[]{i, j + 1, si, (j + 1) % 10 == 0 ? sj - 8 : sj + 1}); // 右边元素入栈
            }
            return res;
        }*/


       /* public void backtracking(int m, int n, int i, int j, int k, int tempTotal) {
            if (calculate(i) + calculate(j) > k) {
                total = tempTotal;
                return;
            }

            if (i > m || j > i) {
                return;
            }

            for (int l = 0; l < n; l++) {
                tempTotal++;
                backtracking(m, n, i + 1, j, k, tempTotal);
                tempTotal--;
            }

        }

        public int calculate(int m) {
            int total = 0;
            while (m != 0) {
                total += m % 10;
                m = m / 10;
            }
            return total;
        }*/

        // DFS
        // https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/by-da-fei-de-tian-kong-dhms/
        public int movingCount(int m, int n, int k) {
            this.m = m;
            this.n = n;
            this.visited = new boolean[m][n];
            return dfs(0, 0, k);
        }

        int m, n;
        boolean[][] visited;

        // 只需要向右和向下递归，参照官解的图
        // https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/ji-qi-ren-de-yun-dong-fan-wei-by-leetcode-solution/
        public int dfs(int i, int j, int k) {
            if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j] == true) return 0;
            if (calculate(i) + calculate(j) > k) return 0;

            // 已经走过
            visited[i][j] = false;

            // 当前格 + 往下走 + 往右走
            return 1 + dfs(i + 1, j, k) + dfs(i, j + 1, k);
        }

        public int calculate(int m) {
            int sum = 0;
            while (m != 0) {
                sum += m % 10;
                m /= 10;
            }
            return sum;
        }

    }
//leetcode submit region end(Prohibit modification and deletion)

}
